#ifndef	ALICE_H
#define	ALICE_H

#if	defined( _MSC_VER ) && ( _MSV_VER > 1020 )
#pragma once
#endif

#include <WinSock2.h>
#include <MSWSock.h>
#include <Windows.h>

namespace alice {

#ifndef	_USRDLL
#define	ALICEAPI	__declspec(dllimport)
#else
#define	ALICEAPI	__declspec(dllexport)
#endif

#define	INLINE	inline

/******************************************************************************
 * WSA EXTENSION API
 ********/
template<typename T>
INLINE T GetWSAFuncPtr( SOCKET );

template<>
INLINE LPFN_TRANSMITFILE GetWSAFuncPtr<LPFN_TRANSMITFILE>( SOCKET _socket ) {
	GUID _ApiID = WSAID_TRANSMITFILE;
	LPFN_TRANSMITFILE _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_ACCEPTEX GetWSAFuncPtr<LPFN_ACCEPTEX>( SOCKET _socket ) {
	GUID _ApiID = WSAID_ACCEPTEX;
	LPFN_ACCEPTEX _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_GETACCEPTEXSOCKADDRS GetWSAFuncPtr<LPFN_GETACCEPTEXSOCKADDRS>( SOCKET _socket ) {
	GUID _ApiID = WSAID_GETACCEPTEXSOCKADDRS;
	LPFN_GETACCEPTEXSOCKADDRS _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_TRANSMITPACKETS GetWSAFuncPtr<LPFN_TRANSMITPACKETS>( SOCKET _socket ) {
	GUID _ApiID = WSAID_TRANSMITPACKETS;
	LPFN_TRANSMITPACKETS _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_CONNECTEX GetWSAFuncPtr<LPFN_CONNECTEX>( SOCKET _socket ) {
	GUID _ApiID = WSAID_CONNECTEX;
	LPFN_CONNECTEX _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_DISCONNECTEX GetWSAFuncPtr<LPFN_DISCONNECTEX>( SOCKET _socket ) {
	GUID _ApiID = WSAID_DISCONNECTEX;
	LPFN_DISCONNECTEX _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_WSARECVMSG GetWSAFuncPtr<LPFN_WSARECVMSG>( SOCKET _socket ) {
	GUID _ApiID = WSAID_WSARECVMSG;
	LPFN_WSARECVMSG _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_WSASENDMSG GetWSAFuncPtr<LPFN_WSASENDMSG>( SOCKET _socket ) {
	GUID _ApiID = WSAID_WSASENDMSG;
	LPFN_WSASENDMSG _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}

template<>
INLINE LPFN_WSAPOLL GetWSAFuncPtr<LPFN_WSAPOLL>( SOCKET _socket ) {
	GUID _ApiID = WSAID_WSAPOLL;
	LPFN_WSAPOLL _pfn;
	DWORD dwBytesRTN;
	if( 0 == WSAIoctl( _socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &_ApiID, sizeof( _ApiID ), 
		&_pfn, sizeof( _pfn ), &dwBytesRTN, NULL, NULL ) )
	{
		return _pfn;
	}
	return NULL;
}


/******************************************************************************
 * IOCP
 ********/
class ALICEAPI CIOCP {
public:
	CIOCP( DWORD NumberOfConcurrentThreads );
	~CIOCP( void );
	BOOL AssociateDevice( HANDLE FileHandle, ULONG_PTR CompletionKey );

private:
	HANDLE m_hIOCP;
};


/******************************************************************************
 * SOCKET
 ********/
class ALICEAPI CSocket {
public:
	CSocket();
	CSocket( SOCKET );
	~CSocket( void );
	BOOL Create( int af, int type, int protocol );
	VOID Close( void );

	operator SOCKET( void ) const;

private:
	SOCKET m_hSocket;
};


/******************************************************************************
 * FILE
 ********/
class ALICEAPI CFile {
public:
	CFile( void );
	CFile( HANDLE );
	CFile( LPCWSTR );
	~CFile( void );

	BOOL Create( LPCWSTR, DWORD, DWORD, DWORD );
	VOID Close( void );
};

class ALICEAPI CMappingFile {

};

class ALICEAPI CTemporaryFile {
public:
	CTemporaryFile( void );
	~CTemporaryFile( void );
	operator HANDLE( void ) const;

private:
	HANDLE m_hFile;
};

}

#endif	// ALICE_H